package com.platform.base.service.impl;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.platform.base.domain.*;
import com.platform.base.mapper.BaseLocationMapper;
import com.platform.base.mapper.CollectorInfoMapper;
import com.platform.base.mapper.MeterTypeMapper;
import com.platform.common.constant.UserConstants;
import com.platform.common.exception.BusinessException;
import com.platform.common.utils.DateUtils;
import com.platform.common.utils.StringUtils;
import com.platform.common.utils.netty.NettyUtil;
import com.platform.common.utils.rabbit.RabbitUtils;
import com.platform.common.utils.redis.RedisRun;
import com.platform.common.utils.redis.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.platform.base.mapper.MeterInfoMapper;
import com.platform.base.service.IMeterInfoService;
import com.platform.common.core.text.Convert;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import javax.annotation.PostConstruct;

/**
 * 热信息Service业务层处理
 * 
 * @author wangqi
 * @date 2020-09-26
 */
@Service
public class MeterInfoServiceImpl extends ServiceImpl<MeterInfoMapper,MeterInfo> implements IMeterInfoService
{
    @Autowired
    private MeterInfoMapper meterInfoMapper;

    @Autowired
    private MeterTypeMapper meterTypeMapper;

    @Autowired
    private BaseLocationMapper baseLocationMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RabbitUtils rabbitUtils;

    @Autowired
    private CollectorInfoMapper collectorInfoMapper;

    /**
     * 查询热信息列表
     * 
     * @param meterInfo 热信息
     * @return 热信息
     */
    @Override
    public List<MeterInfo> selectMeterInfoList(MeterInfo meterInfo)
    {
        return meterInfoMapper.selectMeterInfoList(meterInfo);
    }

    /**
     * 查询热信息列表
     *
     * @return 热信息
     */
    @Override
    public List<MeterInfo> selectCollectorInfoEq()
    {
        return meterInfoMapper.selectCollectorInfoEq();
    }

    /**
     * 查询热信息列表
     *
     * @return 热信息
     */
    @Override
    public List<MeterInfo> selectMeterInfoEq(String collectorId)
    {
        return meterInfoMapper.selectMeterInfoEq(collectorId);
    }
    /**
     * 查询热信息列表
     *
     * @param locationId 热信息
     * @return 热信息
     */
    @Override
    public List<MeterInfo> selectMeterInfoBylocationId(String locationId)
    {
        return meterInfoMapper.selectMeterInfoBylocationId(locationId);
    }

    /**
     * 查询热表信息
     *
     * @param meterId 热表Id
     * @return 热表信息
     */
    @Override
    public MeterInfo selectMeterInfoById(String meterId){
        MeterInfo meterInfo = meterInfoMapper.selectMeterInfoById(meterId);
        return meterInfo;
    }

    /**
     * 新增热信息
     * 
     * @param meterInfo 热信息
     * @return 结果
     */
    @Override
    public int insertMeterInfo(MeterInfo meterInfo)
    {
        meterInfo.setCreateTime(DateUtils.getNowDate());
        return meterInfoMapper.insert(meterInfo);
    }

    /**
     * 修改热信息
     * 
     * @param meterInfo 热信息
     * @return 结果
     */
    @Override
    public int updateMeterInfo(MeterInfo meterInfo)
    {
        meterInfo.setUpdateTime(DateUtils.getNowDate());
        return meterInfoMapper.updateById(meterInfo);
    }

    /**
     * 删除热信息对象
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteMeterInfoByIds(String ids)
    {
        return meterInfoMapper.deleteMeterInfoByIds(Convert.toStrArray(ids));
    }

    /**
     * 校验热表是否唯一
     *
     * @param meterInfo 热表信息
     * @return 结果
     */
    @Override
    public String checkMeterUnique(MeterInfo meterInfo){
        MeterInfo info = meterInfoMapper.selectById(meterInfo.getMeterId());
        if (StringUtils.isNotNull(info))
        {
            return UserConstants.METER_ID_NOT_UNIQUE;
        }
        return UserConstants.METER_ID_UNIQUE;
    }

    /**
     * 根据采集器ID更新热表登记状态
     *
     * @param collectorId 采集器信息
     * @return 结果
     */
    @Override
    public int updateMeterInfoByCollectorId(String collectorId){
        return meterInfoMapper.updateMeterInfoByCollectorId(collectorId);
    }

    /**
     * 导入热表信息数据
     *
     * @param infoList 热表信息数据
     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
     * @param operName 操作用户
     * @return 结果
     */
    @Override
    public String importInfo(List<MeterInfo> infoList, Boolean isUpdateSupport, String operName)
    {
        if (StringUtils.isNull(infoList) || infoList.size() == 0)
        {
            throw new BusinessException("导入热表信息数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (MeterInfo info : infoList)
        {
            try
            {
                //查询热表类型信息
                MeterType type = null;
                if(info.getTypeName()!=null && !info.getTypeName().equals("")){
                    List<MeterType> list = meterTypeMapper.selectList(new QueryWrapper<MeterType>().eq("type_name", info.getTypeName()));
                    if(list!=null && list.size()>0){
                        type = list.get(0);
                        info.setTypeId(type.getTypeId());
                    }else{
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 热表型号不存在");
                        continue;
                    }
                }
                //查询采集器地址信息
                BaseLocation location = null;
                if(info.getLocationName()!=null && !info.getLocationName().equals("")){
                    List<BaseLocation> list = baseLocationMapper.selectList(new QueryWrapper<BaseLocation>().eq("location_name", info.getLocationName()));
                    if(list!=null && list.size()>0){
                        location = list.get(0);
                        info.setLocationId(location.getLocationId());
                    }
                }
                // 校验采集器是否存在
                MeterInfo f = meterInfoMapper.selectById(info.getMeterId());
                if (StringUtils.isNull(f))
                {
                    info.setCreateBy(operName);
                    info.setCreateTime(DateUtils.getNowDate());
                    this.insertMeterInfo(info);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、热表 " + info.getMeterId() + " 导入成功");
                }
                else if (isUpdateSupport)
                {
                    info.setUpdateBy(operName);
                    info.setUpdateTime(DateUtils.getNowDate());
                    this.updateMeterInfo(info);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、热表 " + info.getMeterId() + " 更新成功");
                }
                else
                {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 已存在");
                }
            }
            catch (Exception e)
            {
                failureNum++;
                String msg = "<br/>" + failureNum + "、热表 " + info.getMeterId() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0)
        {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new BusinessException(failureMsg.toString());
        }
        else
        {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * 热表登记
     * @param meterIds 热表信息
     * @param operName 操作用户
     * @return
     * @throws Exception
     */
    @Override
    public String registerInfo(String[] meterIds, String operName) throws InterruptedException {
        int failureNum = 0;
        int successNum = 0;
        StringBuilder failureMsg = new StringBuilder();
        StringBuilder successMsg = new StringBuilder();
        for(String meterId : meterIds){
            MeterInfo info = meterInfoMapper.selectMeterInfoById(meterId);
            CollectorInfo collectorInfo = collectorInfoMapper.selectCollectorInfoById(info.getCollectorId());
            int ccount = collectorInfo.getMeterCount();
            if(info.getCollectorId() == null || info.getCollectorId().equals("")){
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 未关联采集器");
                continue;
            }
            if(ccount>250){
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、热表登记超过250个上限");
                continue;
            }

            //判断采集器是否在线
            boolean status = redisUtil.hHasKey("sys-netty", info.getCollectorId());
            if(!status){
                failureNum++;
                CollectorInfo cinfo = collectorInfoMapper.selectCollectorInfoById(info.getCollectorId());
                cinfo.setOnlineStatus(Integer.valueOf(0));
                cinfo.setCollectorId(info.getCollectorId());
                collectorInfoMapper.updateById(cinfo);
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + "关联的采集器" + info.getCollectorId() + " 已离线");
                continue;
            }
            //获取采集器高位
            String cenhigh = info.getCollectorId().substring(0,2);
            //获取采集器低位
            String cenlow = info.getCollectorId().substring(2,4);
            String add3 = meterId.substring(0,2);
            String add4 = meterId.substring(2,4);
            String add5 = meterId.substring(4,6);
            String add6 = meterId.substring(6,8);
            //控制码
            String cont = "03"; //代表登记
            String factory = info.getFactory().getFactoryCode();
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(add3)+NettyUtil.get10HexNum(add4)+NettyUtil.get10HexNum(add5)+NettyUtil.get10HexNum(add6)+NettyUtil.get10HexNum(cont)+NettyUtil.get10HexNum(factory);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA "+ cenlow +" "+ cenhigh + " " + add3 + " " + add4 + " " + add5 + " " + add6 + " " + cont + " " + info.getFactory().getFactoryCode() + " 00 00 00 00 00 " + check + " FF ";
            String responseStr = response.replace(" ", "");
            rabbitUtils.writeToClient(info.getCollectorId(), responseStr, "热表"+meterId+"登记");
            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch, redisUtil, meterId, cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            redisUtil.del(meterId);
            if(result.equals("00") || result.equals("01")){
                info.setRegisterFlag("1");
                info.setUpdateBy(operName);
                info.setUpdateTime(DateUtils.getNowDate());
                meterInfoMapper.updateById(info);
                successNum++;
                successMsg.append("<br/>" + successNum + "、热表 " + info.getMeterId() + " 登记成功");
            }else{
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 登记失败");
            }
        }
        if(failureNum>0){
            failureMsg.insert(0, "很抱歉，热表登记失败！共 " + failureNum + " 条数热表登记失败，错误如下：");
            throw new BusinessException(failureMsg.toString());
        }else{
            successMsg.insert(0, "恭喜您，热表已全部登记成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * 热表注销
     * @param meterIds 热表信息
     * @param operName 操作用户
     * @return
     * @throws Exception
     */
    @Override
    public String cancelInfo(String[] meterIds, String operName) throws InterruptedException {
        int failureNum = 0;
        int successNum = 0;
        StringBuilder failureMsg = new StringBuilder();
        StringBuilder successMsg = new StringBuilder();
        for(String meterId : meterIds){
            MeterInfo info = null;

            if(redisUtil.hHasKey("meter-info", meterId)){
                info = (MeterInfo) redisUtil.hget("meter-info", meterId);
            }else{
                info = meterInfoMapper.selectMeterInfoById(meterId);
                redisUtil.hset("meter-info", meterId, info, 60000);
            }

            if(info.getCollectorId() == null || info.getCollectorId().equals("")){
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 未关联采集器");
                continue;
            }

            //判断采集器是否在线
            boolean status = redisUtil.hHasKey("sys-netty", info.getCollectorId());
            if(!status){
                failureNum++;
                CollectorInfo cinfo = collectorInfoMapper.selectCollectorInfoById(info.getCollectorId());
                cinfo.setOnlineStatus(Integer.valueOf(0));
                cinfo.setCollectorId(info.getCollectorId());
                collectorInfoMapper.updateById(cinfo);
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + "关联的采集器" + info.getCollectorId() + " 已离线");
                continue;
            }
            //获取采集器高位
            String cenhigh = info.getCollectorId().substring(0,2);
            //获取采集器低位
            String cenlow = info.getCollectorId().substring(2,4);
            String add3 = meterId.substring(0,2);
            String add4 = meterId.substring(2,4);
            String add5 = meterId.substring(4,6);
            String add6 = meterId.substring(6,8);
            //控制码
            String cont = "04";
            String factory = info.getFactory().getFactoryCode();
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(add3)+NettyUtil.get10HexNum(add4)+NettyUtil.get10HexNum(add5)+NettyUtil.get10HexNum(add6)+NettyUtil.get10HexNum(cont)+NettyUtil.get10HexNum(factory);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA "+ cenlow +" "+ cenhigh + " " + add3 + " " + add4 + " " + add5 + " " + add6 + " " + cont + " " + info.getFactory().getFactoryCode() + " 00 00 00 00 00 " + check + " FF ";
            String responseStr = response.replace(" ", "");
            rabbitUtils.writeToClient(info.getCollectorId(), responseStr, "热表"+meterId+"注销");
            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch, redisUtil, meterId, cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            redisUtil.del(meterId);
            if(result.equals("00") || result.equals("02")){
                info.setRegisterFlag("0");
                info.setUpdateBy(operName);
                info.setUpdateTime(DateUtils.getNowDate());
                meterInfoMapper.updateById(info);
                successNum++;
                successMsg.append("<br/>" + successNum + "、热表 " + info.getMeterId() + " 注销成功");
            }else{
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 注销失败");
            }
        }
        if(failureNum>0){
            failureMsg.insert(0, "很抱歉，热表注销失败！共 " + failureNum + " 条数热表注销失败，错误如下：");
            throw new BusinessException(failureMsg.toString());
        }else{
            successMsg.insert(0, "恭喜您，热表已全部注销成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * 热表数据采集
     * @param meterIds 热表信息
     * @return
     * @throws Exception
     */
    @Override
    public String checkInfo(String[] meterIds) throws InterruptedException {
        int failureNum = 0;
        int successNum = 0;
        StringBuilder failureMsg = new StringBuilder();
        StringBuilder successMsg = new StringBuilder();
        for(String meterId : meterIds){
            MeterInfo info = null;

            if(redisUtil.hHasKey("meter-info", meterId)){
                info = (MeterInfo) redisUtil.hget("meter-info", meterId);
            }else{
                info = meterInfoMapper.selectMeterInfoById(meterId);
                redisUtil.hset("meter-info", meterId, info, 60000);
            }

            if(info.getCollectorId() == null || info.getCollectorId().equals("")){
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 未关联采集器");
                continue;
            }

            //判断采集器是否在线
            boolean status = redisUtil.hHasKey("sys-netty", info.getCollectorId());
            if(!status){
                failureNum++;
                CollectorInfo cinfo = collectorInfoMapper.selectCollectorInfoById(info.getCollectorId());
                cinfo.setOnlineStatus(Integer.valueOf(0));
                cinfo.setCollectorId(info.getCollectorId());
                collectorInfoMapper.updateById(cinfo);
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + "关联的采集器" + info.getCollectorId() + " 已离线");
                continue;
            }
            //获取采集器高位
            String cenhigh = info.getCollectorId().substring(0,2);
            
            //获取采集器低位
            String cenlow = info.getCollectorId().substring(2,4);
            String add3 = meterId.substring(0,2);
            String add4 = meterId.substring(2,4);
            String add5 = meterId.substring(4,6);
            String add6 = meterId.substring(6,8);
            //控制码
            String cont = "01";
            String factory = info.getFactory().getFactoryCode();
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(add3)+NettyUtil.get10HexNum(add4)+NettyUtil.get10HexNum(add5)+NettyUtil.get10HexNum(add6)+NettyUtil.get10HexNum(cont)+NettyUtil.get10HexNum(factory);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA "+ cenlow +" "+ cenhigh + " " + add3 + " " + add4 + " " + add5 + " " + add6 + " " + cont + " " + info.getFactory().getFactoryCode() + " 00 00 00 00 00 " + check + " FF ";
            String responseStr = response.replace(" ", "");
            rabbitUtils.writeToClient(info.getCollectorId(), responseStr, "热表"+meterId+"数据采集");
            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch, redisUtil, meterId, cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            redisUtil.del(meterId);
            if(!result.equals("00")){
                failureNum++;
                failureMsg.append("<br/>" + failureNum + "、热表 " + info.getMeterId() + " 读取失败");
            }else{
                successNum++;
                successMsg.append("<br/>" + successNum + "、热表 " + info.getMeterId() + " 读取成功");
            }
        }
        if(failureNum>0){
            failureMsg.insert(0, "很抱歉，热表采集失败！共 " + failureNum + " 条数热表采集失败，错误如下：");
            throw new BusinessException(failureMsg.toString());
        }else{
            successMsg.insert(0, "恭喜您，热表已全部采集成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }
}
